<template>
  <div class="min-h-screen py-8 px-4 sm:px-6 lg:px-8">
    <div class="max-w-7xl mx-auto">
      <!-- 页面标题 -->
      <div class="text-center mb-12">
        <h1 class="text-4xl font-bold mb-4 tech-text">Web Audio API</h1>
        <p class="text-gray-300 text-lg">
          强大的音频处理和合成功能，支持音频可视化、音效处理和音乐创作
        </p>
      </div>

      <!-- 浏览器支持提示 -->
      <div v-if="!isSupported" class="tech-card mb-8 border-yellow-600">
        <div class="flex items-center mb-4">
          <i class="i-carbon-warning text-yellow-500 text-xl mr-3"></i>
          <h3 class="text-xl font-semibold text-yellow-500">浏览器支持提示</h3>
        </div>
        <p class="text-gray-300">
          您的浏览器不支持 Web Audio API。此功能需要现代浏览器支持。
        </p>
      </div>

      <!-- 振荡器音调生成器 -->
      <div class="tech-card mb-8">
        <h2 class="text-2xl font-semibold mb-6 text-white">振荡器音调生成器</h2>
        
        <div class="bg-gray-800 rounded-lg p-6 mb-6">
          <div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
            <div>
              <label class="text-white font-semibold mb-2 block">波形类型</label>
              <select
                v-model="waveType"
                class="w-full bg-gray-700 text-white px-4 py-3 rounded-lg border border-gray-600 focus:border-tech-accent outline-none"
              >
                <option value="sine">正弦波 (Sine)</option>
                <option value="square">方波 (Square)</option>
                <option value="sawtooth">锯齿波 (Sawtooth)</option>
                <option value="triangle">三角波 (Triangle)</option>
              </select>
            </div>

            <div>
              <label class="text-white font-semibold mb-2 block">频率: {{ frequency }} Hz</label>
              <input
                v-model.number="frequency"
                type="range"
                min="20"
                max="2000"
                step="1"
                class="w-full"
              >
            </div>
          </div>

          <div class="mb-6">
            <label class="text-white font-semibold mb-2 block">音量: {{ Math.round(volume * 100) }}%</label>
            <input
              v-model.number="volume"
              type="range"
              min="0"
              max="1"
              step="0.01"
              class="w-full"
            >
          </div>

          <div class="flex gap-3">
            <button
              @click="playTone"
              :disabled="isPlaying"
              class="tech-button flex-1 disabled:opacity-50 disabled:cursor-not-allowed"
            >
              <i class="i-carbon-play-filled mr-2"></i>
              播放音调
            </button>

            <button
              @click="stopTone"
              :disabled="!isPlaying"
              class="bg-red-600 hover:bg-red-700 text-white px-6 py-3 rounded-lg transition-colors flex-1 disabled:opacity-50 disabled:cursor-not-allowed"
            >
              <i class="i-carbon-stop-filled mr-2"></i>
              停止
            </button>
          </div>
        </div>

        <div class="bg-gray-800 rounded-lg p-4">
          <div class="text-gray-300 text-sm space-y-2">
            <p><strong>正弦波：</strong>最纯净的音调，类似长笛</p>
            <p><strong>方波：</strong>明亮、刺耳，类似木管乐器</p>
            <p><strong>锯齿波：</strong>丰富、明亮，类似弦乐器</p>
            <p><strong>三角波：</strong>柔和，介于正弦波和方波之间</p>
          </div>
        </div>
      </div>

      <!-- 简易钢琴 -->
      <div class="tech-card mb-8">
        <h2 class="text-2xl font-semibold mb-6 text-white">虚拟钢琴键盘</h2>
        
        <div class="bg-gray-800 rounded-lg p-6">
          <div class="flex justify-center gap-1 mb-4">
            <button
              v-for="note in pianoKeys"
              :key="note.name"
              @mousedown="playNote(note.frequency)"
              @mouseup="stopNote"
              @mouseleave="stopNote"
              @touchstart.prevent="playNote(note.frequency)"
              @touchend.prevent="stopNote"
              :class="[
                note.isBlack 
                  ? 'bg-gray-900 text-white h-32 w-12 -mx-2 z-10' 
                  : 'bg-white text-black h-48 w-16',
                'rounded-b-lg shadow-lg hover:opacity-80 transition-opacity flex items-end justify-center pb-2 text-xs font-semibold select-none'
              ]"
            >
              {{ note.name }}
            </button>
          </div>

          <div class="text-center text-gray-400 text-sm">
            按住琴键播放音符
          </div>
        </div>
      </div>

      <!-- 音频可视化 -->
      <div class="tech-card mb-8">
        <h2 class="text-2xl font-semibold mb-6 text-white">音频可视化</h2>
        
        <div class="bg-gray-800 rounded-lg p-6 mb-6">
          <canvas
            ref="visualizerCanvas"
            width="800"
            height="200"
            class="w-full bg-gray-900 rounded-lg"
          ></canvas>
        </div>

        <div class="flex gap-3 mb-6">
          <button
            @click="visualizerType = 'frequency'"
            :class="[
              visualizerType === 'frequency' 
                ? 'bg-tech-accent' 
                : 'bg-gray-700 hover:bg-gray-600',
              'text-white px-6 py-3 rounded-lg transition-colors'
            ]"
          >
            <i class="i-carbon-chart-bar mr-2"></i>
            频谱图
          </button>

          <button
            @click="visualizerType = 'waveform'"
            :class="[
              visualizerType === 'waveform' 
                ? 'bg-tech-accent' 
                : 'bg-gray-700 hover:bg-gray-600',
              'text-white px-6 py-3 rounded-lg transition-colors'
            ]"
          >
            <i class="i-carbon-wave mr-2"></i>
            波形图
          </button>
        </div>

        <div>
          <label class="text-white font-semibold mb-2 block">上传音频文件</label>
          <input
            ref="audioFileInput"
            type="file"
            accept="audio/*"
            @change="handleAudioFile"
            class="hidden"
          >
          <button
            @click="audioFileInput?.click()"
            class="tech-button mb-4"
          >
            <i class="i-carbon-document-add mr-2"></i>
            选择音频文件
          </button>

          <div v-if="audioFileName" class="mb-4">
            <div class="bg-gray-800 rounded-lg p-4 flex items-center justify-between">
              <div class="flex items-center gap-3">
                <i class="i-carbon-music text-2xl text-tech-accent"></i>
                <div>
                  <div class="text-white font-semibold">{{ audioFileName }}</div>
                  <div class="text-gray-400 text-sm">{{ audioDuration }}</div>
                </div>
              </div>
              <button
                @click="clearAudioFile"
                class="text-red-400 hover:text-red-300"
              >
                <i class="i-carbon-close text-xl"></i>
              </button>
            </div>
          </div>

          <div v-if="audioElement" class="flex gap-3">
            <button
              @click="toggleAudioPlayback"
              class="tech-button flex-1"
            >
              <i :class="isAudioPlaying ? 'i-carbon-pause-filled' : 'i-carbon-play-filled'" class="mr-2"></i>
              {{ isAudioPlaying ? '暂停' : '播放' }}
            </button>

            <button
              @click="stopAudioPlayback"
              class="bg-red-600 hover:bg-red-700 text-white px-6 py-3 rounded-lg transition-colors"
            >
              <i class="i-carbon-stop-filled mr-2"></i>
              停止
            </button>
          </div>
        </div>
      </div>

      <!-- 音频效果器 -->
      <div class="tech-card mb-8">
        <h2 class="text-2xl font-semibold mb-6 text-white">音频效果器</h2>
        
        <div class="bg-gray-800 rounded-lg p-6 space-y-6">
          <div>
            <div class="flex items-center justify-between mb-2">
              <label class="text-white font-semibold">低音增强</label>
              <label class="relative inline-flex items-center cursor-pointer">
                <input
                  v-model="effects.bass"
                  type="checkbox"
                  class="sr-only peer"
                  @change="updateEffects"
                >
                <div class="w-11 h-6 bg-gray-600 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-tech-accent"></div>
              </label>
            </div>
            <div v-if="effects.bass">
              <label class="text-gray-300 text-sm mb-1 block">增益: {{ bassGain }} dB</label>
              <input
                v-model.number="bassGain"
                type="range"
                min="0"
                max="20"
                step="1"
                class="w-full"
                @input="updateEffects"
              >
            </div>
          </div>

          <div>
            <div class="flex items-center justify-between mb-2">
              <label class="text-white font-semibold">高音增强</label>
              <label class="relative inline-flex items-center cursor-pointer">
                <input
                  v-model="effects.treble"
                  type="checkbox"
                  class="sr-only peer"
                  @change="updateEffects"
                >
                <div class="w-11 h-6 bg-gray-600 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-tech-accent"></div>
              </label>
            </div>
            <div v-if="effects.treble">
              <label class="text-gray-300 text-sm mb-1 block">增益: {{ trebleGain }} dB</label>
              <input
                v-model.number="trebleGain"
                type="range"
                min="0"
                max="20"
                step="1"
                class="w-full"
                @input="updateEffects"
              >
            </div>
          </div>

          <div>
            <div class="flex items-center justify-between mb-2">
              <label class="text-white font-semibold">混响效果</label>
              <label class="relative inline-flex items-center cursor-pointer">
                <input
                  v-model="effects.reverb"
                  type="checkbox"
                  class="sr-only peer"
                  @change="updateEffects"
                >
                <div class="w-11 h-6 bg-gray-600 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-tech-accent"></div>
              </label>
            </div>
            <div v-if="effects.reverb" class="text-gray-400 text-sm">
              混响效果已启用（使用卷积混响）
            </div>
          </div>

          <div>
            <div class="flex items-center justify-between mb-2">
              <label class="text-white font-semibold">失真效果</label>
              <label class="relative inline-flex items-center cursor-pointer">
                <input
                  v-model="effects.distortion"
                  type="checkbox"
                  class="sr-only peer"
                  @change="updateEffects"
                >
                <div class="w-11 h-6 bg-gray-600 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-tech-accent"></div>
              </label>
            </div>
            <div v-if="effects.distortion">
              <label class="text-gray-300 text-sm mb-1 block">强度: {{ distortionAmount }}</label>
              <input
                v-model.number="distortionAmount"
                type="range"
                min="0"
                max="100"
                step="1"
                class="w-full"
                @input="updateEffects"
              >
            </div>
          </div>
        </div>
      </div>

      <!-- 3D 音频定位 -->
      <div class="tech-card mb-8">
        <h2 class="text-2xl font-semibold mb-6 text-white">3D 音频空间定位</h2>
        
        <div class="bg-gray-800 rounded-lg p-8">
          <div class="relative w-full aspect-square max-w-md mx-auto mb-6">
            <div class="absolute inset-0 border-2 border-gray-600 rounded-full"></div>
            <div class="absolute inset-8 border border-gray-700 rounded-full"></div>
            <div class="absolute inset-16 border border-gray-700 rounded-full"></div>
            
            <!-- 听者（中心） -->
            <div class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-8 h-8 bg-blue-500 rounded-full flex items-center justify-center shadow-lg">
              <i class="i-carbon-user text-white"></i>
            </div>

            <!-- 音源 -->
            <div
              @mousedown="startDraggingSound"
              @touchstart.prevent="startDraggingSound"
              :style="{
                left: soundPosition.x + '%',
                top: soundPosition.y + '%'
              }"
              class="absolute -translate-x-1/2 -translate-y-1/2 w-10 h-10 bg-red-500 rounded-full cursor-move flex items-center justify-center shadow-lg hover:scale-110 transition-transform"
            >
              <i class="i-carbon-volume-up text-white"></i>
            </div>
          </div>

          <div class="text-center text-gray-400 text-sm mb-4">
            拖动红色图标移动音源位置，体验 3D 音频效果
          </div>

          <div class="grid grid-cols-2 gap-4 text-center">
            <div class="bg-gray-900 rounded-lg p-4">
              <div class="text-gray-400 text-sm mb-1">X 位置</div>
              <div class="text-white text-xl font-semibold">{{ Math.round((soundPosition.x - 50) / 5) }}</div>
            </div>
            <div class="bg-gray-900 rounded-lg p-4">
              <div class="text-gray-400 text-sm mb-1">Y 位置</div>
              <div class="text-white text-xl font-semibold">{{ Math.round((soundPosition.y - 50) / 5) }}</div>
            </div>
          </div>

          <button
            @click="toggle3DAudio"
            class="tech-button w-full mt-4"
          >
            <i :class="is3DAudioPlaying ? 'i-carbon-stop-filled' : 'i-carbon-play-filled'" class="mr-2"></i>
            {{ is3DAudioPlaying ? '停止 3D 音频' : '播放 3D 音频' }}
          </button>
        </div>
      </div>

      <!-- 音频录制 -->
      <div class="tech-card mb-8">
        <h2 class="text-2xl font-semibold mb-6 text-white">麦克风录制</h2>
        
        <div class="bg-gray-800 rounded-lg p-6">
          <div v-if="!hasRecording" class="text-center py-8">
            <i class="i-carbon-microphone text-6xl text-gray-600 mb-4 block"></i>
            <button
              @click="startRecording"
              :disabled="isRecording"
              class="tech-button disabled:opacity-50 disabled:cursor-not-allowed"
            >
              <i class="i-carbon-record mr-2"></i>
              {{ isRecording ? '录制中...' : '开始录制' }}
            </button>
            
            <div v-if="isRecording" class="mt-4">
              <div class="text-white text-2xl font-semibold mb-2">{{ recordingTime }}s</div>
              <button
                @click="stopRecording"
                class="bg-red-600 hover:bg-red-700 text-white px-6 py-3 rounded-lg transition-colors"
              >
                <i class="i-carbon-stop-filled mr-2"></i>
                停止录制
              </button>
            </div>
          </div>

          <div v-else>
            <div class="flex items-center justify-between mb-4">
              <div class="flex items-center gap-3">
                <i class="i-carbon-microphone text-3xl text-tech-accent"></i>
                <div>
                  <div class="text-white font-semibold">录音 {{ recordingTime }}s</div>
                  <div class="text-gray-400 text-sm">点击播放或下载</div>
                </div>
              </div>
              <button
                @click="clearRecording"
                class="text-red-400 hover:text-red-300"
              >
                <i class="i-carbon-trash-can text-xl"></i>
              </button>
            </div>

            <div class="flex gap-3">
              <button
                @click="playRecording"
                class="tech-button flex-1"
              >
                <i class="i-carbon-play-filled mr-2"></i>
                播放录音
              </button>

              <button
                @click="downloadRecording"
                class="bg-green-600 hover:bg-green-700 text-white px-6 py-3 rounded-lg transition-colors"
              >
                <i class="i-carbon-download mr-2"></i>
                下载
              </button>
            </div>
          </div>
        </div>
      </div>

      <!-- API 信息 -->
      <div class="tech-card">
        <h3 class="text-xl font-semibold mb-4 text-white">API 信息</h3>
        <div class="space-y-4 text-gray-300">
          <div>
            <h4 class="font-semibold text-tech-accent mb-2">浏览器支持</h4>
            <p>Chrome 35+, Firefox 25+, Safari 14.1+, Edge 79+</p>
          </div>
          <div>
            <h4 class="font-semibold text-tech-accent mb-2">核心概念</h4>
            <ul class="list-disc list-inside space-y-1">
              <li><code class="bg-gray-800 px-2 py-1 rounded">AudioContext</code> - 音频处理上下文</li>
              <li><code class="bg-gray-800 px-2 py-1 rounded">OscillatorNode</code> - 振荡器节点，生成音调</li>
              <li><code class="bg-gray-800 px-2 py-1 rounded">GainNode</code> - 音量控制节点</li>
              <li><code class="bg-gray-800 px-2 py-1 rounded">AnalyserNode</code> - 音频分析节点</li>
              <li><code class="bg-gray-800 px-2 py-1 rounded">BiquadFilterNode</code> - 滤波器节点</li>
              <li><code class="bg-gray-800 px-2 py-1 rounded">ConvolverNode</code> - 卷积混响节点</li>
              <li><code class="bg-gray-800 px-2 py-1 rounded">PannerNode</code> - 3D 音频定位节点</li>
              <li><code class="bg-gray-800 px-2 py-1 rounded">WaveShaperNode</code> - 波形整形节点（失真效果）</li>
            </ul>
          </div>
          <div>
            <h4 class="font-semibold text-tech-accent mb-2">基本用法</h4>
            <pre class="bg-gray-800 p-4 rounded text-sm overflow-x-auto">
<span class="text-gray-500">// 创建音频上下文</span>
<span class="text-blue-400">const</span> audioContext = <span class="text-blue-400">new</span> AudioContext();

<span class="text-gray-500">// 创建振荡器</span>
<span class="text-blue-400">const</span> oscillator = audioContext.createOscillator();
oscillator.type = <span class="text-green-400">'sine'</span>;
oscillator.frequency.value = <span class="text-orange-400">440</span>; <span class="text-gray-500">// A4 音符</span>

<span class="text-gray-500">// 创建增益节点（音量控制）</span>
<span class="text-blue-400">const</span> gainNode = audioContext.createGain();
gainNode.gain.value = <span class="text-orange-400">0.5</span>;

<span class="text-gray-500">// 连接节点</span>
oscillator.connect(gainNode);
gainNode.connect(audioContext.destination);

<span class="text-gray-500">// 播放</span>
oscillator.start();
oscillator.stop(audioContext.currentTime + <span class="text-orange-400">1</span>);</pre>
          </div>
          <div>
            <h4 class="font-semibold text-tech-accent mb-2">音频可视化</h4>
            <pre class="bg-gray-800 p-4 rounded text-sm overflow-x-auto">
<span class="text-gray-500">// 创建分析器</span>
<span class="text-blue-400">const</span> analyser = audioContext.createAnalyser();
analyser.fftSize = <span class="text-orange-400">2048</span>;

<span class="text-gray-500">// 连接音频源</span>
source.connect(analyser);
analyser.connect(audioContext.destination);

<span class="text-gray-500">// 获取频率数据</span>
<span class="text-blue-400">const</span> dataArray = <span class="text-blue-400">new</span> Uint8Array(analyser.frequencyBinCount);
analyser.getByteFrequencyData(dataArray);

<span class="text-gray-500">// 获取时域数据（波形）</span>
analyser.getByteTimeDomainData(dataArray);</pre>
          </div>
          <div>
            <h4 class="font-semibold text-tech-accent mb-2">使用场景</h4>
            <ul class="list-disc list-inside space-y-1 text-sm">
              <li>音乐播放器和音频编辑器</li>
              <li>游戏音效和背景音乐</li>
              <li>语音通话和视频会议</li>
              <li>音频可视化和频谱分析</li>
              <li>虚拟乐器和音乐合成器</li>
              <li>音频效果器和混音台</li>
              <li>3D 游戏中的空间音频</li>
              <li>语音识别和音频处理</li>
            </ul>
          </div>
          <div>
            <h4 class="font-semibold text-tech-accent mb-2">优势特性</h4>
            <ul class="list-disc list-inside space-y-1 text-sm">
              <li><strong>低延迟：</strong>精确控制音频播放时间</li>
              <li><strong>模块化：</strong>通过节点连接构建复杂音频图</li>
              <li><strong>高性能：</strong>在独立线程中处理音频</li>
              <li><strong>精确控制：</strong>采样级别的音频操作</li>
              <li><strong>丰富效果：</strong>内置多种音频处理节点</li>
              <li><strong>3D 音频：</strong>支持空间音频定位</li>
            </ul>
          </div>
          <div>
            <h4 class="font-semibold text-tech-accent mb-2">最佳实践</h4>
            <ul class="list-disc list-inside space-y-1 text-sm">
              <li>用户交互后再创建 AudioContext（避免自动播放限制）</li>
              <li>重用 AudioContext 实例，避免创建过多</li>
              <li>使用 AudioWorklet 处理自定义音频算法</li>
              <li>合理设置 fftSize 平衡性能和精度</li>
              <li>完成后断开节点连接释放资源</li>
              <li>使用 Web Audio API Polyfill 提高兼容性</li>
            </ul>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'

// 类型定义
interface PianoKey {
  name: string
  frequency: number
  isBlack: boolean
}

interface Effects {
  bass: boolean
  treble: boolean
  reverb: boolean
  distortion: boolean
}

// 响应式状态
const isSupported = ref(true)

// 音频上下文
let audioContext: AudioContext | null = null
let oscillator: OscillatorNode | null = null
let gainNode: GainNode | null = null
let analyser: AnalyserNode | null = null

// 振荡器参数
const waveType = ref<OscillatorType>('sine')
const frequency = ref(440)
const volume = ref(0.3)
const isPlaying = ref(false)

// 钢琴键
const pianoKeys = ref<PianoKey[]>([
  { name: 'C', frequency: 261.63, isBlack: false },
  { name: 'C#', frequency: 277.18, isBlack: true },
  { name: 'D', frequency: 293.66, isBlack: false },
  { name: 'D#', frequency: 311.13, isBlack: true },
  { name: 'E', frequency: 329.63, isBlack: false },
  { name: 'F', frequency: 349.23, isBlack: false },
  { name: 'F#', frequency: 369.99, isBlack: true },
  { name: 'G', frequency: 392.00, isBlack: false },
  { name: 'G#', frequency: 415.30, isBlack: true },
  { name: 'A', frequency: 440.00, isBlack: false },
  { name: 'A#', frequency: 466.16, isBlack: true },
  { name: 'B', frequency: 493.88, isBlack: false }
])

let noteOscillator: OscillatorNode | null = null

// 可视化
const visualizerCanvas = ref<HTMLCanvasElement | null>(null)
const visualizerType = ref<'frequency' | 'waveform'>('frequency')
let visualizerAnimationFrame: number | null = null

// 音频文件
const audioFileInput = ref<HTMLInputElement | null>(null)
const audioFileName = ref('')
const audioDuration = ref('')
const audioElement = ref<HTMLAudioElement | null>(null)
const isAudioPlaying = ref(false)
let audioSource: MediaElementAudioSourceNode | null = null

// 音频效果
const effects = ref<Effects>({
  bass: false,
  treble: false,
  reverb: false,
  distortion: false
})
const bassGain = ref(10)
const trebleGain = ref(10)
const distortionAmount = ref(50)

let bassFilter: BiquadFilterNode | null = null
let trebleFilter: BiquadFilterNode | null = null
let distortionNode: WaveShaperNode | null = null

// 3D 音频
const soundPosition = ref({ x: 70, y: 30 })
const is3DAudioPlaying = ref(false)
let pannerNode: PannerNode | null = null
let spatialOscillator: OscillatorNode | null = null
let isDragging = ref(false)

// 录音
const isRecording = ref(false)
const hasRecording = ref(false)
const recordingTime = ref(0)
let mediaRecorder: MediaRecorder | null = null
let recordedChunks: Blob[] = []
let recordingInterval: ReturnType<typeof setInterval> | null = null
let recordingBlob: Blob | null = null

// 初始化
onMounted(() => {
  isSupported.value = !!(window.AudioContext || (window as any).webkitAudioContext)
  
  if (isSupported.value) {
    initAudioContext()
    startVisualizer()
  }

  // 添加拖动监听
  document.addEventListener('mousemove', handleDragSound)
  document.addEventListener('mouseup', stopDraggingSound)
  document.addEventListener('touchmove', handleDragSound)
  document.addEventListener('touchend', stopDraggingSound)
})

// 清理
onUnmounted(() => {
  if (visualizerAnimationFrame) {
    cancelAnimationFrame(visualizerAnimationFrame)
  }
  if (audioContext) {
    audioContext.close()
  }
  if (recordingInterval) {
    clearInterval(recordingInterval)
  }

  document.removeEventListener('mousemove', handleDragSound)
  document.removeEventListener('mouseup', stopDraggingSound)
  document.removeEventListener('touchmove', handleDragSound)
  document.removeEventListener('touchend', stopDraggingSound)
})

// 初始化音频上下文
const initAudioContext = () => {
  if (!audioContext) {
    audioContext = new (window.AudioContext || (window as any).webkitAudioContext)()
    
    // 创建分析器
    analyser = audioContext.createAnalyser()
    analyser.fftSize = 2048
    analyser.connect(audioContext.destination)

    // 创建效果器节点
    bassFilter = audioContext.createBiquadFilter()
    bassFilter.type = 'lowshelf'
    bassFilter.frequency.value = 200

    trebleFilter = audioContext.createBiquadFilter()
    trebleFilter.type = 'highshelf'
    trebleFilter.frequency.value = 3000

    distortionNode = audioContext.createWaveShaper()
  }
}

// 播放音调
const playTone = () => {
  if (!audioContext || isPlaying.value) return

  initAudioContext()

  oscillator = audioContext.createOscillator()
  gainNode = audioContext.createGain()

  oscillator.type = waveType.value
  oscillator.frequency.value = frequency.value
  gainNode.gain.value = volume.value

  oscillator.connect(gainNode)
  gainNode.connect(analyser!)

  oscillator.start()
  isPlaying.value = true
}

// 停止音调
const stopTone = () => {
  if (oscillator) {
    oscillator.stop()
    oscillator = null
    isPlaying.value = false
  }
}

// 播放音符
const playNote = (freq: number) => {
  if (!audioContext) return

  initAudioContext()

  if (noteOscillator) {
    noteOscillator.stop()
  }

  noteOscillator = audioContext.createOscillator()
  const noteGain = audioContext.createGain()

  noteOscillator.type = 'sine'
  noteOscillator.frequency.value = freq
  noteGain.gain.value = 0.3

  noteOscillator.connect(noteGain)
  noteGain.connect(analyser!)

  noteOscillator.start()
}

// 停止音符
const stopNote = () => {
  if (noteOscillator) {
    noteOscillator.stop()
    noteOscillator = null
  }
}

// 启动可视化
const startVisualizer = () => {
  const draw = () => {
    if (!visualizerCanvas.value || !analyser) {
      visualizerAnimationFrame = requestAnimationFrame(draw)
      return
    }

    const canvas = visualizerCanvas.value
    const ctx = canvas.getContext('2d')
    if (!ctx) return

    const bufferLength = analyser.frequencyBinCount
    const dataArray = new Uint8Array(bufferLength)

    if (visualizerType.value === 'frequency') {
      analyser.getByteFrequencyData(dataArray)

      ctx.fillStyle = '#111827'
      ctx.fillRect(0, 0, canvas.width, canvas.height)

      const barWidth = (canvas.width / bufferLength) * 2.5
      let x = 0

      for (let i = 0; i < bufferLength; i++) {
        const barHeight = (dataArray[i] / 255) * canvas.height

        const gradient = ctx.createLinearGradient(0, canvas.height - barHeight, 0, canvas.height)
        gradient.addColorStop(0, '#3b82f6')
        gradient.addColorStop(1, '#8b5cf6')

        ctx.fillStyle = gradient
        ctx.fillRect(x, canvas.height - barHeight, barWidth, barHeight)

        x += barWidth + 1
      }
    } else {
      analyser.getByteTimeDomainData(dataArray)

      ctx.fillStyle = '#111827'
      ctx.fillRect(0, 0, canvas.width, canvas.height)

      ctx.lineWidth = 2
      ctx.strokeStyle = '#3b82f6'
      ctx.beginPath()

      const sliceWidth = canvas.width / bufferLength
      let x = 0

      for (let i = 0; i < bufferLength; i++) {
        const v = dataArray[i] / 128.0
        const y = (v * canvas.height) / 2

        if (i === 0) {
          ctx.moveTo(x, y)
        } else {
          ctx.lineTo(x, y)
        }

        x += sliceWidth
      }

      ctx.lineTo(canvas.width, canvas.height / 2)
      ctx.stroke()
    }

    visualizerAnimationFrame = requestAnimationFrame(draw)
  }

  draw()
}

// 处理音频文件
const handleAudioFile = (event: Event) => {
  const input = event.target as HTMLInputElement
  const file = input.files?.[0]

  if (!file) return

  audioFileName.value = file.name

  if (audioElement.value) {
    audioElement.value.pause()
    audioElement.value = null
  }

  audioElement.value = new Audio()
  const url = URL.createObjectURL(file)
  audioElement.value.src = url

  audioElement.value.addEventListener('loadedmetadata', () => {
    const duration = audioElement.value!.duration
    const minutes = Math.floor(duration / 60)
    const seconds = Math.floor(duration % 60)
    audioDuration.value = `${minutes}:${seconds.toString().padStart(2, '0')}`
  })

  // 连接到音频上下文
  initAudioContext()
  if (audioContext && !audioSource) {
    audioSource = audioContext.createMediaElementSource(audioElement.value)
    connectAudioNodes()
  }
}

// 连接音频节点
const connectAudioNodes = () => {
  if (!audioSource || !analyser) return

  // 断开之前的连接
  audioSource.disconnect()

  let currentNode: AudioNode = audioSource

  // 根据效果连接节点
  if (effects.value.bass && bassFilter) {
    currentNode.connect(bassFilter)
    currentNode = bassFilter
  }

  if (effects.value.treble && trebleFilter) {
    currentNode.connect(trebleFilter)
    currentNode = trebleFilter
  }

  if (effects.value.distortion && distortionNode) {
    currentNode.connect(distortionNode)
    currentNode = distortionNode
  }

  currentNode.connect(analyser)
}

// 更新效果
const updateEffects = () => {
  if (bassFilter) {
    bassFilter.gain.value = effects.value.bass ? bassGain.value : 0
  }

  if (trebleFilter) {
    trebleFilter.gain.value = effects.value.treble ? trebleGain.value : 0
  }

  if (distortionNode) {
    const curve = effects.value.distortion ? makeDistortionCurve(distortionAmount.value) : null
    distortionNode.curve = curve as any
  }

  if (audioSource) {
    connectAudioNodes()
  }
}

// 生成失真曲线
const makeDistortionCurve = (amount: number): Float32Array | null => {
  const k = amount
  const samples = 44100
  const curve = new Float32Array(samples)
  const deg = Math.PI / 180

  for (let i = 0; i < samples; i++) {
    const x = (i * 2) / samples - 1
    curve[i] = ((3 + k) * x * 20 * deg) / (Math.PI + k * Math.abs(x))
  }

  return curve
}

// 切换播放
const toggleAudioPlayback = () => {
  if (!audioElement.value) return

  if (isAudioPlaying.value) {
    audioElement.value.pause()
  } else {
    audioElement.value.play()
  }

  isAudioPlaying.value = !isAudioPlaying.value
}

// 停止播放
const stopAudioPlayback = () => {
  if (!audioElement.value) return

  audioElement.value.pause()
  audioElement.value.currentTime = 0
  isAudioPlaying.value = false
}

// 清除音频文件
const clearAudioFile = () => {
  if (audioElement.value) {
    audioElement.value.pause()
    audioElement.value = null
  }

  audioFileName.value = ''
  audioDuration.value = ''
  isAudioPlaying.value = false
  audioSource = null

  if (audioFileInput.value) {
    audioFileInput.value.value = ''
  }
}

// 3D 音频控制
const toggle3DAudio = () => {
  if (is3DAudioPlaying.value) {
    stop3DAudio()
  } else {
    start3DAudio()
  }
}

const start3DAudio = () => {
  if (!audioContext) return

  initAudioContext()

  spatialOscillator = audioContext.createOscillator()
  pannerNode = audioContext.createPanner()
  const spatialGain = audioContext.createGain()

  spatialOscillator.type = 'sine'
  spatialOscillator.frequency.value = 440
  spatialGain.gain.value = 0.3

  // 设置听者位置（原点）
  audioContext.listener.positionX.value = 0
  audioContext.listener.positionY.value = 0
  audioContext.listener.positionZ.value = 0

  // 设置音源位置
  updatePannerPosition()

  spatialOscillator.connect(pannerNode)
  pannerNode.connect(spatialGain)
  spatialGain.connect(audioContext.destination)

  spatialOscillator.start()
  is3DAudioPlaying.value = true
}

const stop3DAudio = () => {
  if (spatialOscillator) {
    spatialOscillator.stop()
    spatialOscillator = null
  }
  is3DAudioPlaying.value = false
}

const updatePannerPosition = () => {
  if (!pannerNode) return

  const x = (soundPosition.value.x - 50) / 10
  const y = (soundPosition.value.y - 50) / 10

  pannerNode.positionX.value = x
  pannerNode.positionY.value = -y
  pannerNode.positionZ.value = -5
}

// 拖动音源
const startDraggingSound = () => {
  isDragging.value = true
}

const handleDragSound = (event: MouseEvent | TouchEvent) => {
  if (!isDragging.value) return

  const container = (event.currentTarget as HTMLElement)?.parentElement
  if (!container) return

  const rect = container.getBoundingClientRect()
  
  let clientX: number, clientY: number
  
  if (event instanceof MouseEvent) {
    clientX = event.clientX
    clientY = event.clientY
  } else {
    clientX = event.touches[0].clientX
    clientY = event.touches[0].clientY
  }

  const x = ((clientX - rect.left) / rect.width) * 100
  const y = ((clientY - rect.top) / rect.height) * 100

  soundPosition.value = {
    x: Math.max(0, Math.min(100, x)),
    y: Math.max(0, Math.min(100, y))
  }

  updatePannerPosition()
}

const stopDraggingSound = () => {
  isDragging.value = false
}

// 录音功能
const startRecording = async () => {
  try {
    const stream = await navigator.mediaDevices.getUserMedia({ audio: true })
    
    mediaRecorder = new MediaRecorder(stream)
    recordedChunks = []

    mediaRecorder.ondataavailable = (event) => {
      if (event.data.size > 0) {
        recordedChunks.push(event.data)
      }
    }

    mediaRecorder.onstop = () => {
      recordingBlob = new Blob(recordedChunks, { type: 'audio/webm' })
      hasRecording.value = true
      
      // 停止所有音轨
      stream.getTracks().forEach(track => track.stop())
    }

    mediaRecorder.start()
    isRecording.value = true
    recordingTime.value = 0

    recordingInterval = setInterval(() => {
      recordingTime.value++
    }, 1000)
  } catch (error) {
    console.error('录音失败:', error)
    alert('无法访问麦克风，请检查权限设置')
  }
}

const stopRecording = () => {
  if (mediaRecorder && isRecording.value) {
    mediaRecorder.stop()
    isRecording.value = false
    
    if (recordingInterval) {
      clearInterval(recordingInterval)
    }
  }
}

const playRecording = () => {
  if (!recordingBlob) return

  const audio = new Audio()
  audio.src = URL.createObjectURL(recordingBlob)
  audio.play()
}

const downloadRecording = () => {
  if (!recordingBlob) return

  const url = URL.createObjectURL(recordingBlob)
  const a = document.createElement('a')
  a.href = url
  a.download = `recording-${Date.now()}.webm`
  a.click()
  URL.revokeObjectURL(url)
}

const clearRecording = () => {
  recordingBlob = null
  hasRecording.value = false
  recordingTime.value = 0
  recordedChunks = []
}
</script>

<style scoped>
/* 自定义样式 */
input[type="range"] {
  -webkit-appearance: none;
  appearance: none;
  background: transparent;
  cursor: pointer;
}

input[type="range"]::-webkit-slider-track {
  background: #374151;
  height: 0.5rem;
  border-radius: 0.25rem;
}

input[type="range"]::-moz-range-track {
  background: #374151;
  height: 0.5rem;
  border-radius: 0.25rem;
}

input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 1.25rem;
  height: 1.25rem;
  border-radius: 50%;
  background: #3b82f6;
  cursor: pointer;
  margin-top: -0.375rem;
}

input[type="range"]::-moz-range-thumb {
  width: 1.25rem;
  height: 1.25rem;
  border-radius: 50%;
  background: #3b82f6;
  cursor: pointer;
  border: none;
}
</style>
